/*
 * Copyright (c) 2005-2012 Imperas Software Ltd., www.imperas.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */


////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//                W R I T T E N   B Y   I M P E R A S   I G E N               //
//                                                                            //
//                          Wed Feb 24 15:15:28 2010                          //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

#include "pse.igen.h"

typedef Uns32 input;
typedef Uns32 output;

static struct {
    output reset;
    output nmi0;
    output nmi1;
    output nmi2;
    output intp;
    output mireti;
    output intack;
    input  ireset;
    input  nmi[64];
    input  i[256];
} ports;

#define BYTE_ACCESS(_addr,_user) *(Uns8*)((Uns32)(_user) | ((Uns32)(_addr) & 1))

static void writeByteOrShort(void *addr, Uns32 bytes, void *user, Uns32 data) {
    if (bytes == 1) {
        BYTE_ACCESS(addr,user) = data;
    } else {
        *(Uns16*)user = data;
    }
}

static Uns32 readByteOrShort(void *addr, Uns32 bytes, void *user) {
    if (bytes == 1) {
        return BYTE_ACCESS(addr,user);
    } else {
        return *(Uns16*)user;
    }
}

//////////////////////////////// Callback stubs ////////////////////////////////
// #define PPM_NET_CB(_NAME) void _NAME(ppmNetValue value, void *userData)
PPM_NET_CB(P_i) {
    // YOUR CODE HERE (P_i)
    // bhmPrintf("INTC pin i%d -> %d\n", (Uns32)userData, value);
    Uns32 index = (Uns32)userData;

    if (ports.i[index] != value) {
        //
        // If an interrupt line changes state look at the corresponding
        // INTF/INTR Register for that bit
        //
        if (value) {
        } else {
        }
    }

    ports.i[index] = value;
}

PPM_NET_CB(P_mireti) {
    // YOUR CODE HERE (P_mireti)
    // bhmPrintf("INTC pin mireti -> %d\n", value);
}

PPM_NET_CB(P_intack) {
    // YOUR CODE HERE (P_intack)
    // bhmPrintf("INTC pin intack -> %d\n", value);
}

PPM_NET_CB(P_ireset) {
    // bhmPrintf("INTC pin ireset -> %d\n", value);
}

PPM_NET_CB(P_nmi) {
    // bhmPrintf("INTC pin nmi -> %d\n", value);

    Uns32 index = (Uns32)userData;

    Uns32 wire_or = 0;
    if ((ports.nmi[index] != value) && value) {
        wire_or = 1;
    }

    ppmWriteNet(handles.nmi0, wire_or);
    ports.nmi[index] = value;
}

//
// This is a bit confusing because the Register is actually
// 16 bits but the documentation implies 8 bit writes
//
PPM_REG_WRITE_CB(writeIC) {
    // A write to the IC register also requires that the
    // corresonding bit in IMR is written
    writeByteOrShort(addr, bytes, user, data & 0xc7);
}
PPM_REG_READ_CB(readIC) {
    return readByteOrShort(addr, bytes, user);
}

//
// Interrupt mask register can be written as byte or short
//
PPM_REG_WRITE_CB(writeIMR) {
    // A write to the IMR register also requires that the
    // corresonding bit in IC is written
    writeByteOrShort(addr, bytes, user, data);
}

PPM_REG_READ_CB(readIMR) {
    return readByteOrShort(addr, bytes, user);
}

//
// External interrupt edge detection, byte or short
//
PPM_REG_WRITE_CB(writeINTM) {
    writeByteOrShort(addr, bytes, user, data);
}
PPM_REG_READ_CB(readINTM) {
    return readByteOrShort(addr, bytes, user);
}

PPM_REG_WRITE_CB(writeISEL) {
    // YOUR CODE HERE (writeISEL)
    *(Uns8*)user = data;
}

PPM_REG_WRITE_CB(writeISF) {
    // YOUR CODE HERE (writeISF)
    *(Uns8*)user = data;
}

PPM_CONSTRUCTOR_CB(constructor) {
    // YOUR CODE HERE (pre constructor)
    periphConstructor();
    // YOUR CODE HERE (post constructor)
}

